package ferp.center.server.servlet.config;

import com.google.appengine.api.memcache.Expiration;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import ferp.center.network.request.RequestConfigGet;
import ferp.center.network.response.ResponseConfigGet;
import ferp.center.server.Action;
import ferp.center.server.entity.Config;
import ferp.center.server.poll.Polls;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;

/**
 * User: igorgok
 * Date: 12/9/12 5:12 PM
 */
public class ConfigGet extends HttpServlet
{
  @SuppressWarnings("unchecked")
  public static Config current(EntityManager em)
  {
    MemcacheService mcs = MemcacheServiceFactory.getMemcacheService();
    Config c = (Config)mcs.get(CURRENT_CONFIG);

    if (c == null)
    {
      // try to load from the DB
      if ((c = load(em)) != null)
        // make the cache expire in 12 hours
        mcs.put(CURRENT_CONFIG, c, Expiration.byDeltaSeconds(12 * 60 * 60));
    }
    else
      logger.info("using cached configuration");

    return c;
  }

  @SuppressWarnings("unchecked")
  public static Config load(EntityManager em)
  {
    Query q = em.createQuery("SELECT c FROM Config c ORDER BY c.created DESC");

    q.setMaxResults(1);
    List<Config> configs = q.getResultList();

    // get only one configuration object
    return configs.size() > 0 ? configs.get(0) : null;
  }

  public static void uncache()
  {
    Action.logger().info("deleting cached configuration...");

    MemcacheServiceFactory.getMemcacheService().delete(CURRENT_CONFIG);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
  {
    Action.execute(request, response, RequestConfigGet.class, new Action.Read<RequestConfigGet, ResponseConfigGet>()
    {
      @SuppressWarnings("unchecked")
      public ResponseConfigGet run(EntityManager em, RequestConfigGet input) throws IOException
      {
        ResponseConfigGet result = new ResponseConfigGet();
        Config config = current(em);

        if (config != null)
        {
          boolean nnv2 = input.version != null && input.version.code > 80;
          // client v81 does not send last bid NN id
          boolean v81bug = nnv2 && input.version.code == 81;

          // send configuration id
          result.id = config.getId();

          logger.info("configuration ID: old=[" + input.id + "], current=[" + result.id + "]");

          // send bid NN configuration
          result.bidding = new ResponseConfigGet.Bidding();
          result.bidding.enable = config.getBidNNEnabled();
          result.bidding.threshold = config.getBidNNThreshold();

          // send NN data only if needed
          // clients [v > 80] provide bid NN id, so it is used instead of configuration id
          if (input.debug || input.id != result.id || (nnv2 && !v81bug && input.lastBidNNID != config.getBidNNID()))
          {
            // NN data
            result.bidding.id = config.getBidNNID();
            result.bidding.nnj = nnv2 ? config.getBidNNData() : config.getBidNNJson();

            logger.info("sending " + (nnv2 ? "new" : "old") + " bid NN configuration, size=" + result.bidding.nnj.length());
          }
          else
            logger.info("bid NN configuration not sent");

          // only if levels remote updating enabled
          if (config.getLevelsEnabled())
          {
            result.levels = new ResponseConfigGet.Levels();
            result.levels.data = config.getLevelsData();
          }

          // messages support starts from version ???
          //if (input.version != null && input.version.code > ??? && config.getMessagesEnabled())
          //  result.messages = Action.gson().toJson(Messages.get(input.locale, input.version.code, input.date));

          // get interstitial flag
          result.ad = config.getAd();
        }

        result.poll = Polls.get(input.locale, input.lastPollID);

        return result;
      }
    });
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
  {
    doPost(request, response);
  }

  // memcached key for the current configuration object
  private static final String CURRENT_CONFIG = "current-config";
  // logger
  private static final Logger logger = Logger.getLogger(ConfigGet.class.getSimpleName());
}
